package com.ruoyi.system.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.AESUtil;
import com.ruoyi.common.utils.JWTUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.system.domain.WeChatConfig;
import com.ruoyi.system.domain.dto.WxAccessToken;
import com.ruoyi.system.domain.dto.WxDecryptedUserInfo;
import com.ruoyi.system.domain.dto.WxError;
import com.ruoyi.system.domain.dto.WxUserInfo;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.util.HashMap;
import java.util.Map;

/**
 * @auther czg
 * @date 2020/9/19 5:23 下午
 */

@Component
public class WxProcessor {

    private static final Logger logger = LoggerFactory.getLogger(WxProcessor.class);

    @Autowired
    private WeChatConfig weChatConfig;

    @Autowired
    private RestTemplate restTemplate;

    public static void main(String[] args) {
        String str = "{\"openId\":\"o2Axq5OwJQqLYzVC3q4qmdgpf4bM\",\"nickName\":\"天空蓝\",\"gender\":1,\"language\":\"zh_CN\",\"city\":\"杭州\",\"province\":\"浙江\",\"country\":\"中国\",\"avatarUrl\":\"https://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTLW9l73adZcrIXiaxDlvnlqurgLO3FmAV2RcXtTExDVKdiacZNocKMAy7wsGtSV75ryAY5zwfKrpb0g/132\",\"unionId\":\"oSfZSt28WBcO-fHi0HE3ljIaWz78\",\"watermark\":{\"timestamp\":1600768458,\"appid\":\"wx864e470b612d6374\"}}";
        WxDecryptedUserInfo info = JSONObject.parseObject(str, WxDecryptedUserInfo.class);
        System.out.println(info);
        System.out.println(info.getErrcode());
    }

    /**
     * 获取微信登录信息
     *
     * @param code
     * @return
     */
    public WxUserInfo queryXcxUserInfoByJscode(String code) {
        //拼接微信请求参数
        String url = getWxOpenUrl() + "/sns/jscode2session?appid=" + getWxAppId() + "&secret=" + getWxSecret()
                + "&js_code=" + code + "&grant_type=authorization_code";
        ResponseEntity<WxUserInfo> resp = null;
        try {
//            RestTemplate restTemplate = new RestTemplate();
            resp = restTemplate.getForEntity(url, WxUserInfo.class);
            if (HttpStatus.OK.equals(resp.getStatusCode())) {
                WxUserInfo wxUserInfo = resp.getBody();
                JWTUtil.createToken("");
                logger.info("wx code2Session response success. {}", JSON.toJSONString(wxUserInfo));
                SpringUtils.getBean(RedisCache.class).setCacheObject("","");
                return wxUserInfo;
            }
            logger.info("wx code2Session response failed. {}", JSON.toJSONString(resp));
        } catch (Exception e) {
            logger.info("wx code2Session response err. {}. {}. {}.", url, JSON.toJSONString(resp), e.getMessage());
            return null;
        }
        return null;
    }

    /**
     * 获得用户accessToken
     *
     * @return
     */
    public WxAccessToken getWxAccessToken() {

        //todo:增加缓存处理
        //expires_in	number	凭证有效时间，单位：秒。目前是7200秒之内的值。
//        String redis_key = "wxappToken:" + appId + ":" + appSecret;
        //WxAccessToken token = redisCache.get(redis_key,WxAccessToken.class);
        WxAccessToken token = null;
        if (null != token) {
            return token;
        } else {
            String url = getWxOpenUrl() + "/cgi-bin/token?grant_type=client_credential&appid=" + getWxAppId() + "&secret=" + getWxSecret();
            ResponseEntity<WxAccessToken> resp = null;
            try {
//                RestTemplate restTemplate = new RestTemplate();
                resp = restTemplate.getForEntity(url, WxAccessToken.class);
                if (null != resp && HttpStatus.OK.equals(resp.getStatusCode())) {
                    WxAccessToken wxAccessToken = resp.getBody();
                    logger.info("wx getAccessToken response success . {}", JSON.toJSONString(wxAccessToken));

                    //xiakun 2019-3-3加入缓存，过期时间置微信返回有效时间后的的4/5（微信目前默认为7200秒）
 /*                   RedisCacheKey redisCacheKey = new RedisCacheKey(redis_key);
                    RedisCacheElement redisCacheElement = new RedisCacheElement(redisCacheKey,wxAccessToken);
                    redisCacheElement.expireAfter(wxAccessToken.getExpires_in().longValue() * 4 / 5);
                    redisCache.put(redisCacheElement);*/
                    return wxAccessToken;
                }
                logger.info("wx getAccessToken response failed. {}", JSON.toJSONString(resp));
            } catch (Exception e) {
                logger.info("wx getAccessToken response err. {}. {}. {}.", url, JSON.toJSONString(resp), e.getMessage());
                return null;
            }
        }
        return null;
    }

    /**
     * 小程序生成二维码方式，无限制
     *
     * @param accessToken
     * @param scene
     * @param page
     * @param width
     * @return
     * @throws
     */
    public Object getWxQrCodeByTpye(String accessToken, String scene, String page, Integer width) {
        String wxUrl;
        Map<String, Object> param = new HashMap<>(16);
        param.put("width", width);
        wxUrl = getWxOpenUrl() + "/wxa/getwxacodeunlimit?access_token=" + accessToken;
        param.put("scene", scene);
        param.put("page", page);
        return getWxQrCode(wxUrl, param);
    }

    /**
     * 获取小程序二维码
     *
     * @param url
     * @param param
     * @return
     */
    private byte[] getWxQrCode(String url, Map param) {
        ResponseEntity<byte[]> resp = null;
        WxError resCode;
        byte[] result = null;
        try {
            String jsonStr = JSON.toJSONString(param);
//            RestTemplate restTemplate = new RestTemplate();
            resp = restTemplate.postForEntity(url, jsonStr, byte[].class);
//            if (null != resp && HttpStatus.OK.equals(resp.getStatusCode())) {
            if (null != resp) {
                result = resp.getBody();
/*                String wxRes = new String(result);
                resCode = JSON.parseObject(wxRes, WxError.class);
                LoggerFactory.generalInfo("获取小程序二维码. request:{0}, response:{1}", jsonStr, JSON.toJSONString(resCode));
                if (resCode != null && resCode.getErrcode() > 0) {
                    throw new UserBusinessException(String.valueOf(resCode.getErrcode()), resCode.getErrmsg());
                }*/
                return result;
            }
            logger.info("小获取小程序二维码失败. {}", JSON.toJSONString(resp));
        } catch (Exception e) {
            logger.info("获取小程序二维码异常. {}. {}. {}.", url, new String(resp.getBody()), e.getMessage());
        }
        return null;
    }

    /**
     * 解密用户敏感数据
     * 解密手机号和用户信息是同一个方法
     * 可以通过watermark中的appId验证
     */
    public WxDecryptedUserInfo decodeUserPhone(String encryptedData, String iv, String sessionKey) {
        WxDecryptedUserInfo userInfo = decodeUser(encryptedData, iv, sessionKey);
        if (null == userInfo) {
            logger.error("小程序 用户信息解密为空.");
        }
        String appId = weChatConfig.getWxAppId();
        if (userInfo.getWatermark() == null || !appId.equals(userInfo.getWatermark().getAppid())) {
            logger.error("小程序 用户信息解密 数据水印校验失败.{}", JSON.toJSONString(userInfo));
        }
        return userInfo;
    }

    public WxDecryptedUserInfo decodeUser(String encryptedData, String iv, String session_key) {
        WxDecryptedUserInfo userInfo = new WxDecryptedUserInfo();
        try {
            String userInfoStr = decodeInfo(encryptedData, iv, session_key);
            logger.info("小程序 用户信息解密 rawData:{}", userInfoStr);
            if (StringUtils.isNotBlank(userInfoStr)) {
                userInfo = JSONObject.parseObject(userInfoStr, WxDecryptedUserInfo.class);
                if (userInfo.getErrcode() != null) {
                    logger.error("小程序 用户信息解密出错 errcode{}. errmsg{}.", userInfo.getErrcode() + "", userInfo.getErrmsg());
                }
            }
        } catch (Exception e) {
            logger.error("小程序 用户信息解密出错  errmsg{}", e.getMessage());
        }
        return userInfo;
    }

    public String decodeInfo(String encryptedData, String iv, String session_key) throws InvalidAlgorithmParameterException, UnsupportedEncodingException {
        byte[] resultByte = AESUtil.instance.wxDecrypt(Base64.decodeBase64(encryptedData), Base64.decodeBase64(session_key), Base64.decodeBase64(iv));
        if (null != resultByte && resultByte.length > 0) {
            String userInfoStr = new String(resultByte, StandardCharsets.UTF_8);
            return userInfoStr;
        }
        return null;
    }

    private String getWxOpenUrl() {
        return weChatConfig.getOpenWxUrl();
    }

    private String getWxAppId() {
        return weChatConfig.getWxAppId();
    }

    private String getWxSecret() {
        return weChatConfig.getWxSecret();
    }

}
